/**
 * HappyFarm Service v2
 *
 * Author: Cong Liu
 * Date: 06/16/2009
 *
 **/

(function(){with(HappyFarm.util) {
	
function BaseService(){
    this._state = new BaseService.SNew;
    this._timers = {};
    this._init = this._start = this._stop = this._pause = this._resume = function(){};
}

BaseService.prototype = {
    init: function() {
        this._state = this._state.transform(BaseService.SERVICE_INIT_STATUS, this._init, this);
    },
    start: function() {
        this._state = this._state.transform(BaseService.SERVICE_RUNNING_STATUS, this._start, this);
    },
    stop: function() {
        this._state = this._state.transform(BaseService.SERVICE_STOPPED_STATUS, function() {
            this._stop();
            this.destroy();
        }, this);
    },
    pause: function() {
        this._state = this._state.transform(BaseService.SERVICE_PASUED_STATUS, this._pause, this);
    },
    resume: function() {
        this._state = this._state.transform(BaseService.SERVICE_RUNNING_STATUS, this._resume, this);
    },
    getStatus: function(){
        return this._state.status;
    },
    destroy: function() {
        for each(var timer in this._timers) {
            this.clearInterval(timer[0]);
        }
    },
    setInterval: function(callback, interval) {
        var timer = setInterval(callback, interval);
        this._timers[timer] = [timer, true];
    },
    clearInterval: function(timer) {
        if(this._timers[timer] && this._timers[timer][1]) {
            clearInterval(timer);
            this._timers[timer][1] = false;
        }
    }
};

extend(BaseService, {
    SERVICE_NEW_STATUS: 1,
    SERVICE_INIT_STATUS: 2,
    SERVICE_RUNNING_STATUS: 3,
    SERVICE_PAUSED_STATUS: 4,
    SERVICE_STOPPED_STATUS: 5,
    SNew: function() {
        this.status = BaseService.SERVICE_NEW_STATUS;
        this.transform = function(input, func, obj){
            if(input == BaseService.SERVICE_INIT_STATUS) {
                func.apply(obj);
                return new BaseService.SInit;
            } else if(input == BaseService.SERVICE_NEW_STATUS) {
                return this;
            }
            hfException('invalid service state transform');
        };
    },
    SInit: function() {
        this.status = BaseService.SERVICE_INIT_STATUS;
        this.transform = function(input, func, obj) {
            if(input == BaseService.SERVICE_RUNNING_STATUS) {
                func.apply(obj);
                return new BaseService.SRunning;
            } else if(input == BaseService.SERVICE_STOPPED_STATUS) {
                func.apply(obj);
                return new BaseService.SStoped;
            } else if(input == BaseService.SERVICE_INIT_STATUS) {
                return this;
            }
            hfException('invalid service state transform');
        };
    },
    SRunning: function() {
        this.status = BaseService.SERVICE_RUNNING_STATUS;
        this.transform = function(input, func, obj) {
            if(input == BaseService.SERVICE_STOPPED_STATUS) {
                func.apply(obj);
                return new BaseService.SStopped;
            } else if(input == BaseService.SERVICE_PASUED_STATUS) {
                func.apply(obj);
                return new BaseService.SPaused;
            } else if(input == BaseService.SERVICE_RUNNING_STATUS) {
                return this;
            }
            hfException('invalid service state transform');
        };
    },
    SStopped: function() {
        this.status = BaseService.SERVICE_STOPPED_STATUS;
        this.transform = function(input, func, obj) {
            if(input == BaseService.SERVICE_STOPPED_STATUS)
                return this;
            hfException('invalid service state transform');
        };
    },
    SPaused: function() {
        this.status = BaseService.SERVICE_PAUSED_STATUS;
        this.transform = function(input, func, obj) {
            if(input == BaseService.SERVICE_RUNNING_STATUS) {
                func.apply(obj);
                return new BaseService.SRunning;
            } else if(input == BaseService.SERVICE_STOPPED_STATUS) {
                func.apply(obj);
                return new BaseService.SStopped;
            } else if(input == BaseService.SERVICE_PAUSED_STATUS) {
                return this;
            }
            hfException('invalid service state transform');
        };
    }
});

function ServiceControlManager(){
    this.init();
}

ServiceControlManager.getInstance = function() {
    if(!this._inst) this._inst = new ServiceControlManager;
    return this._inst;
};

ServiceControlManager.prototype = {
    _srvList: {},
    _init: false,
    init: function() {
        if(this._init) return;

        this._init = true;
        var self = this;
        this._timer = setInterval(function(){
            self._sched();
        }, 1000);
    },
    startAll: function() {
        for (var srvName in this._srvList) {
            try{
                this.startService(srvName);
            } catch (e) {}
        }
    },
    stopAll: function() {
        for (var srvName in this._srvList) {
            try{
                this.stopService(srvName);
            } catch (e) {}
        }
    },
    pauseAll: function() {
        for (var srvName in this._srvList) {
            try{
                this.pauseService(srvName);
            } catch (e) {}
        }
    },
    resumeAll: function() {
        for (var srvName in this._srvList) {
            try{
                this.resumeService(srvName);
            } catch (e) {}
        }
    },
    _sched: function() {
        for(var srv in this._srvList) {
            if(this.getServiceStatus(srv) == BaseService.SERVICE_RUNNING_STATUS) {
                var sInst = this._srvList[srv].inst;
                if(sInst._sched) sInst._sched();
            }
        }
    },
    registerService: function(srv, clazz) {
        if(this._srvList[srv]) hfException('registerService: service '+srv+' already exists!');
        this._srvList[srv] = {
            clazz: clazz,
            inst: null
        };
    },
    unregisterService: function(srv) {
        if(this._srvList[srv]) hfException('unregisterService: service '+srv+' does not exists');
        var sInst = this._srvList[srv].inst;
        if(sInst && s.Inst.getStatus() != BaseService.SERVICE_STOPPED_STATUS) hfException('service '+srv+' should be stopped before being unregistered');
        delete this._srvList[srv];
    },
    startService: function(srv) {
        if(!this._srvList[srv]) hfException('startService: service '+srv+' does not exists');
        var s = this._srvList[srv];
        if(!s.inst ||	//service instance not created
            s.inst.getStatus() == BaseService.SERVICE_STOPPED_STATUS) {	//service is stopped
            s.inst = new s.clazz();
            s.inst.init();
        }
        s.inst.start();
    },
    stopService: function(srv) {
        if(!this._srvList[srv]) hfException('stopService: service '+srv+' does not exists');
        if(this._srvList[srv].inst) this._srvList[srv].inst.stop();
    },
    restartService: function(srv) {
        this.stopService(srv);
        this.startService(srv);
    },
    pauseService: function(srv) {
        if(!this._srvList[srv]) hfException('pauseService: service '+srv+' does not exists');
        if(this._srvList[srv].inst) this._srvList[srv].inst.pause();
    },
    resumeService: function(srv) {
        if(!this._srvList[srv]) hfException('resumeService: service '+srv+' does not exists');
        if(this._srvList[srv].inst) this._srvList[srv].inst.resume();
    },
    callService: function(srv, func, params) {
        if(!this._srvList[srv]) hfException('callService: service '+srv+' does not exists');
        var sInst = this._srvList[srv].inst;
        if(this.getServiceStatus(srv) != BaseService.SERVICE_RUNNING_STATUS) {	//service is not running
            hfException('service '+srv+' is not running');
        }
        sInst['srv'+func].apply(sInst, params);
    },
    getServiceStatus: function(srv) {
        if(!this._srvList[srv]) hfException('getServiceStatus: service '+srv+' does not exists');
        var sInst = this._srvList[srv].inst;
        return sInst?sInst.getStatus():BaseService.SERVICE_NEW_STATUS;
    },
    getServiceInstance: function(srv) {
        if(!this._srvList[srv]) hfException('getServiceInstance: service '+srv+' does not exists');
        var s = this._srvList[srv];
        if(!s.inst) {
            s.inst = new s.clazz();
            s.inst.init();
        }
        return s.inst;
    },
    getAllServices: function() {
        return [srvName for(srvName in this._srvList)];
    }
};

HappyFarm.service = {
    BaseService: BaseService,
    ServiceControlManager: ServiceControlManager
};
	
}})();
